/*
 * Copyright © 2024-2025 Wenze Wei
 *
 * This file is part of StadionOS.
 *
 * This Source Code Form is subject to the terms of the GNU General Public License, v. 2.0.
 * You can obtain a copy of the GPL at
 * https://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 */

#include "sys/network.h"
#include "../include/malloc.h"
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>

int Ssocket(int domain, int type, int protocol) {
    if (domain != AF_INET) {
        errno = EAFNOSUPPORT;
        return -1;
    }

    int sockfd = syscall(SYS_socket, domain, type, protocol);
    if (sockfd < 0) {
        errno = -sockfd;
        return -1;
    }

    return sockfd;
}

int Sbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
    if (sockfd < 0) {
        errno = EBADF;
        return -1;
    }
    if (!addr || addrlen < sizeof(struct sockaddr)) {
        errno = EINVAL;
        return -1;
    }
    if (addr->sa_family != AF_INET) {
        errno = EAFNOSUPPORT;
        return -1;
    }

    int ret = syscall(SYS_bind, sockfd, addr, addrlen);
    if (ret < 0) {
        errno = -ret;
        return -1;
    }

    return 0;
}

int Slisten(int sockfd, int backlog) {
    if (sockfd < 0) {
        errno = EBADF;
        return -1;
    }
    if (backlog <= 0) {
        errno = EINVAL;
        return -1;
    }

    int ret = syscall(SYS_listen, sockfd, backlog);
    if (ret < 0) {
        errno = -ret;
        return -1;
    }

    return 0;
}

int Saccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
    if (sockfd < 0) {
        errno = EBADF;
        return -1;
    }

    int ret = syscall(SYS_accept, sockfd, addr, addrlen);
    if (ret < 0) {
        errno = -ret;
        return -1;
    }

    return ret;
}

int Sinet_pton(int af, const char *src, void *dst) {
    if (af != AF_INET) {
        errno = EAFNOSUPPORT;
        return 0;
    }

    uint8_t *bytes = (uint8_t *)dst;
    int result = sscanf(src, "%hhu.%hhu.%hhu.%hhu", &bytes[0], &bytes[1], &bytes[2], &bytes[3]);
    if (result != 4) {
        return 0;
    }

    return 1;
}

const char *Sinet_ntop(int af, const void *src, char *dst, size_t size) {
    if (af != AF_INET) {
        errno = EAFNOSUPPORT;
        return NULL;
    }

    const uint8_t *bytes = (const uint8_t *)src;
    snprintf(dst, size, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
    return dst;
}
